package convert;

import java.io.File;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

public class ConvertUtil {
	public static String strFileNameFilter = "Item";
	public static String strClasspath = "bin/";

	// private static String strOPDir = "F:/SDE
	// Uday/workspace/KraterChatJava/flex/convert/";

	public static void main(String[] args) {
		try {
			// get the system classpath
			File classpathElement = new File(strClasspath);
			// cleanUp(new File(strOPDir));

			new ConvertUtil().traverseClasses(classpathElement);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private static void cleanUp(File parFile) {
		deleteDir(parFile);
		parFile.mkdirs();
	}

	private static void deleteDir(File parFile) {
		if (parFile.isDirectory()) {
			File[] childFiles = parFile.listFiles();
			for (int index = 0; index < childFiles.length; index++) {
				deleteDir(childFiles[index]);
			}

		} else if (parFile.isFile()) {
			parFile.delete();
		}
	}

	private void traverseClasses(File parFile) {
		if (parFile.isDirectory()) {
			File[] childFiles = parFile.listFiles();
			for (int index = 0; index < childFiles.length; index++) {
				traverseClasses(childFiles[index]);
			}
		} else if (parFile.isFile()
				&& (parFile.getName().contains(ConvertUtil.strFileNameFilter))) {
			String className = parFile.getPath().replace('\\', '/')
					.replaceFirst(ConvertUtil.strClasspath, "").replace('/',
							'.').replaceFirst(".class", "");
			System.out.println("*************\n");
			convertToAS(className);
		}
	}

	private void convertToAS(String className) {
		StringBuffer strPackageDecl = new StringBuffer();
		StringBuffer strImportsDecl = new StringBuffer("\n");
		StringBuffer strClassDecl = new StringBuffer();
		StringBuffer strFieldAccDecl = new StringBuffer();
		StringBuffer strToStringFunc = new StringBuffer(
				"\n\t\tpublic function toString():String{\n\t\t\treturn \t\""
						+ className + "[\" + ");

		try {
			System.out.println("Converting class" + className);
			Class objClass = Class.forName(className);

			strPackageDecl.append(objClass.getPackage().getName() + "\n{");

			strClassDecl.append("\t[RemoteClass(alias=\"" + objClass.getName()
					+ "\")]\n\t[Bindable]\n");

			String strSuperClass = "";

			if ((objClass.getSuperclass() != null)
					&& (!objClass.getSuperclass().getName().equalsIgnoreCase(
							"java.lang.Object"))) {
				strSuperClass = getConvertClassType(objClass.getSuperclass());
				strImportsDecl.append("\timport " + strSuperClass + ";\n");
				strSuperClass = " extends "
						+ strSuperClass.substring(strSuperClass
								.lastIndexOf('.') + 1);
			}

			if (strSuperClass.toString().contains("extends")) {
				strToStringFunc
						.append("\n\t\t\t\t\"\\n\" + super.toString() + ");
			}

			strClassDecl.append("\tpublic class " + objClass.getSimpleName()
					+ strSuperClass + "\n\t{");

			Field[] arrFields = objClass.getDeclaredFields();

			for (int indexFields = 0; indexFields < arrFields.length; indexFields++) {
				Class fieldClass = arrFields[indexFields].getType();

				String strFieldtype = getConvertClassType(fieldClass);

				/*
				 * So if the current field or its superclass is not mapped, put
				 * the current type in the import
				 */
				if (strFieldtype.indexOf('.') != -1) {
					if (!strImportsDecl.toString().contains(strFieldtype)) {
						strImportsDecl.append("\timport " + strFieldtype
								+ ";\n");
					}

					strFieldtype = strFieldtype.substring(strFieldtype
							.lastIndexOf('.') + 1);
				}
				strFieldAccDecl.append("\t\tpublic var "
						+ arrFields[indexFields].getName() + ":" + strFieldtype
						+ ";\n");
				strToStringFunc.append("\n\t\t\t\t\"\\n"
						+ arrFields[indexFields].getName() + " = \" + "
						+ arrFields[indexFields].getName()
						+ ".toString() + \",\" + ");
			}

			if (arrFields.length != 0) {
				strToStringFunc = new StringBuffer(strToStringFunc.substring(0,
						strToStringFunc.toString().length() - 9)
						+ " + \"]\";\n\t\t}\n");
			} else {
				strToStringFunc = new StringBuffer(strToStringFunc.toString()
						+ "\"]\";\n\t\t}\n");
			}

		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		StringBuffer strClassDef = new StringBuffer();

		strClassDef.append(strPackageDecl);
		strClassDef.append(strImportsDecl + "\n");
		strClassDef.append(strClassDecl + "\n");
		strClassDef.append(strFieldAccDecl);
		strClassDef.append(strToStringFunc);
		strClassDef.append("\t}\n}");

		System.out.println(strClassDef);
	}

	private static Map<String, String> fieldMapping = new HashMap<String, String>();

	public ConvertUtil() {
		fieldMapping.put("java.util.Map", "Array");
		fieldMapping.put("java.util.Date", "Date");
		fieldMapping.put("java.util.Calendar", "Date");
		fieldMapping.put("java.sql.Timestamp", "Date");
		fieldMapping.put("java.sql.Time", "Date");
		fieldMapping.put("java.sql.Date", "Date");
		fieldMapping.put("java.lang.Double", "Number");
		fieldMapping.put("java.lang.Boolean", "Boolean");
		fieldMapping.put("java.lang.Long", "Number");
		fieldMapping.put("java.lang.Float", "Number");
		fieldMapping.put("java.lang.Integer", "Number");
		fieldMapping.put("java.lang.Short", "Number");
		fieldMapping.put("java.lang.Byte", "Number");
		fieldMapping.put("java.math.BigDecimal", "Number");
		fieldMapping.put("java.math.BigInteger", "Number");
		fieldMapping.put("java.util.Map", "Object");
		fieldMapping.put("java.util.HashMap", "Object");
		fieldMapping.put("java.util.TreeMap", "Object");
		fieldMapping.put("java.util.SortedMap", "Object");
		fieldMapping.put("java.lang.String", "String");
		fieldMapping.put("org.w3c.dom.Document", "XML");
		fieldMapping.put("org.w3c.dom.Document", "XMLDocument");
		fieldMapping.put("java.util.Dictionary", "Object");
		fieldMapping.put("java.util.Collection",
				"mx.collections.ArrayCollection");

	}

	private String getConvertClassType(Class targetClass) {
		if (ConvertUtil.fieldMapping.get(targetClass.getName()) != null) {
			return fieldMapping.get(targetClass.getName());
		} else {
			Class[] arrInterface = targetClass.getInterfaces();
			for (int indexIFc = 0; indexIFc < arrInterface.length; indexIFc++) {
				String strFieldtype = getConvertClassType(arrInterface[indexIFc]);
				if (strFieldtype != null) {
					return strFieldtype;
				}
			}

			Class superClass = targetClass.getSuperclass();
			if ((superClass == null)
					|| (superClass.getName()
							.equalsIgnoreCase("java.lang.Object"))) {
				return targetClass.getName();
			}
			if (superClass != null) {
				String strFieldtype = fieldMapping.get(superClass.getName());

				if (strFieldtype != null) {
					return strFieldtype;
				} else {
					return getConvertClassType(superClass);
				}
			} else {
				return targetClass.getName();
			}
		}
	}
}
